home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mm / mm-0.90 / localfile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-18  |  8.3 KB  |  323 lines

  1. /*
  2.  * Copyright (c) 1986, 1990 by The Trustees of Columbia University in
  3.  * the City of New York.  Permission is granted to any individual or
  4.  * institution to use, copy, or redistribute this software so long as it
  5.  * is not sold for profit, provided this copyright notice is retained.
  6.  */
  7.  
  8. /*
  9.  * get the size of a local file
  10.  */
  11. local_get_size(mail)
  12. msgvec *mail;
  13. {
  14.     struct stat sbuf;
  15.     if (fstat(fileno(mail->filep), &sbuf) == 0)
  16.     mail->size = sbuf.st_size;
  17.     else {
  18.     fprintf(stderr,"?Couldn't determine size of %s\n", mail->filename);
  19.     mail->size = 0;
  20.     }
  21. }
  22.  
  23. /*
  24.  * local_contig_open:
  25.  * Contiguous local files are opened the same way, regardless of format...
  26.  */
  27. local_contig_open (mail,flags)
  28. msgvec *mail;
  29. int flags;
  30. {
  31.     FILE *fp;
  32.     char *openflags;            /* how to open the file */
  33.     int err;
  34.     struct stat sbuf;
  35.     int lockable;            /* can we lock it? */
  36.     int upgrade = FALSE;
  37.  
  38.     if (flags & OP_APP)            /* gonna save to this file */
  39.     openflags = "a";        /* write only at end */
  40.     else if (mail->flags & MF_RDONLY)
  41.     openflags = "r";
  42.     else
  43.     openflags = "r+";
  44.     
  45.     /* be careful about opening a file that's already open */
  46.     if (cf && same_file (mail->filename, cf->filename)) {
  47.     if (cf->flags & MF_RDONLY) {    /* current file is read only */
  48.         if (mail->flags & MF_RDONLY) { /* r -> r */
  49.         if (flags & OP_INT)
  50.             fprintf (stderr, "(Rereading %s)\n", mail->filename);
  51.         }
  52.         else {            /* r -> w */
  53.         upgrade = TRUE;        /* open and lock */
  54.         }
  55.     }
  56.     else {                /* current file is read/write */
  57.         if (mail->flags & MF_RDONLY) { /* w -> r */
  58.         unlock_file (cf->filename, fileno(cf->filep));
  59.         mail->filep = NULL;    /* reuse cf since same file */
  60.         return (0);
  61.         }
  62.         else {            /* w -> w */
  63.         if (flags & OP_INT)
  64.             fprintf (stderr, 
  65.                  "?%s already current writable mail file\n", 
  66.                  mail->filename);
  67.         free (mail);
  68.         errno = ETXTBSY;
  69.         return (ETXTBSY);
  70.         }
  71.     }
  72.     }    
  73.  
  74.     if (!upgrade && (flags & OP_APP) || ((mail->flags & MF_RDONLY) == 0)) {
  75.     if (stat (mail->filename, &sbuf) != 0) {
  76.         /*
  77.          * if filename doesn't exist, make sure it gets created
  78.          * with the proper mode.
  79.          */
  80.         int fd = creat (mail->filename, new_file_mode);
  81.         if (fd < 0) {
  82.         fprintf (stderr, "Cannot create %s: %s\n", mail->filename,
  83.              errstr (errno));
  84.         (void) free (mail);    /* XXX bogus! */
  85.         return errno;
  86.         }
  87.         else
  88.         (void) close (fd);
  89.     }
  90.     }
  91.     
  92.     if ((fp = fopen (mail->filename, openflags)) == NULL) {
  93.         if (flags & OP_INT) {        /* interactive? */
  94.         fprintf (stderr, "?Cannot open %s: %s\n", 
  95.              mail->filename, errstr (errno));
  96.     }
  97.     free (mail);
  98.     return (errno);
  99.     }
  100.  
  101.     if (fstat(fileno(fp), &sbuf) == 0) {
  102.     mail->size = sbuf.st_size;
  103.     mail->mtime = sbuf.st_mtime;    /* record_mtime(mail) */
  104.     lockable = ((sbuf.st_mode & S_IFMT) == S_IFREG);
  105.     }
  106.     else {
  107.     fprintf(stderr,"fstat: Couldn't determine size and type of %s\n",
  108.         mail->filename);
  109.     mail->size = 0;
  110.     lockable = FALSE;
  111.     }
  112.  
  113.     if (upgrade) {            /* close first since we are  */
  114.     local_close (cf->filep);    /* about to lock.  too late */
  115.     cf->filep = NULL;        /* if lock succeeds */
  116.     }
  117.     /* if opened for write, lock the file away */
  118.     if (lockable && ((flags & OP_APP) || !(mail->flags & MF_RDONLY))) {
  119.     if (lock_file (mail->filename, fileno (fp)) < 0) {
  120.         if (errno == EINVAL) {
  121.         if (debug)
  122.             fprintf (stderr, "%%File %s could not be locked\n",
  123.                  mail->filename);
  124.         /*
  125.          * pretend we locked it, and hope for the best
  126.          */
  127.         }
  128.         else {
  129.         if (!upgrade)
  130.             local_close(fp);    /* close it again */
  131.         else {
  132.             cf->filep = fp;    /* use this instead */
  133.         }
  134.         if (!(flags & OP_INT)) {
  135.             free (mail);
  136.             return (errno);
  137.         }
  138.         fprintf (stderr, "?Can't lock %s: %s.\n\
  139.  Apparently some other process is accessing this file in read/write mode.\n",
  140.              mail->filename,
  141. #ifdef EWOULDBLOCK
  142.              (errno == EWOULDBLOCK) ? "file is busy" :
  143. #endif
  144.              errstr (errno));
  145.         free (mail);
  146.         return (errno);
  147.         }
  148.     }
  149.     }
  150.  
  151.     mail->filep = fp;
  152.     if (! (flags & OP_APP))        /* don't count if for append */
  153.         local_contig_count (mail);    /* count 'em */
  154.     return 0;                /* no error */
  155. }
  156.  
  157.  
  158. /*
  159.  * local_contig_count:
  160.  * count the messages in this mail file.  For formats which call this
  161.  * routine, (ones which are local, contiguous mail files), this
  162.  * requires reading them all in, so do that and keep in as many as we
  163.  * have room for.  This fills in mail->count and mail->msgs.
  164.  */
  165. local_contig_count (mail)
  166. msgvec *mail;
  167. {
  168.     int alloccnt;            /* how many we've allocated */
  169.     int err;
  170.  
  171.     alloccnt = 10;            /* start with ten messages */
  172.     mail->count = 0;            /* none yet */
  173.     /* get space for headers */
  174.     mail->msgs = (message *) malloc (alloccnt * sizeof (message));
  175.     mail->last_read = 0;        /* haven't read any yet */
  176.     mail->keywords = nil;
  177.     /* read the next one as long as we can */
  178.     while (1) {
  179.     mail->count++;
  180.     mail->msgs[mail->count].msgno = mail->count;
  181.     mail->msgs[mail->count].hdrsum = NULL;
  182.     mail->msgs[mail->count].private = NULL;
  183.     
  184.     err = (*msg_ops[mail->type].rd_msg)(mail, mail->count);
  185.     if (err != RD_OK)
  186.         break;
  187.         if (mail->count+1 == alloccnt)    /* filled 'em all up (except #0) */
  188.         mail->msgs = (message *)
  189.             realloc (mail->msgs, (alloccnt+=10) * sizeof (message));
  190.     }
  191.     /* read 1:n-1, failed on n -> n-1 msgs */
  192.     mail->count--;
  193.  
  194.     if (err == RD_FAIL) {        /* format problem */
  195.     mail->flags |= MF_RDONLY;    /* make file read-only */
  196.  
  197.     fprintf (stderr, "\n\
  198. There is a problem with %s.\n\
  199. MM was unable to read the entire mail file because it appears to have\n\
  200. been corrupted.  You may be able to read some of the messages in this file,\n\
  201. but MM will not add messages to it or allow you to modify it.  See a\n\
  202. consultant or systems administrator for help.\n\n",
  203.          mail->filename);
  204.     if (mail->flags & MF_MAILBOX)
  205.         fprintf (stderr, "\
  206. Since this file is your primary mailbox, you must resolve this\n\
  207. problem before MM can process new mail.  If no assistance is available\n\
  208. now, rename the file so MM won't find it at startup, and a new mailbox\n\
  209. file will be created for you the next time you invoke MM.\n\n");
  210.     }
  211.     /* snug it down to fit just right */
  212.     mail->msgs = (message *) realloc (mail->msgs, 
  213.                       (mail->count+1)*sizeof (message));
  214. }
  215.  
  216. /*
  217.  * local_contig_proben:
  218.  * open a local contiguous file for probin'
  219.  * probe-open = proben -- get it??
  220.  */
  221. int
  222. local_contig_proben (file,fpp)
  223. char *file;
  224. FILE **fpp;
  225. {
  226.     if ((*fpp = fopen (file, "r")) == NULL)
  227.         switch (errno) {        /* nice switch */
  228.     case EACCES:
  229.         return (PR_PERM);        /* couldn't look at it */
  230.     default:
  231.         return (PR_NOEX);        /* say it doesn't exist */
  232.     }
  233.     return (PR_OK);            /* okay, we opened it */
  234. }
  235.  
  236. /*
  237.  * local_close:
  238.  * local files are also mostly closed the same way
  239.  * gotta free up the lock, though that probably gets done automagically
  240.  * when we let go of the file...
  241.  */
  242. local_close (fp)
  243. FILE *fp;
  244. {
  245.     if (fp != NULL)
  246.     fclose (fp);
  247. }
  248.  
  249. /*
  250.  * given a new filename to open and a file pointer for a file we already
  251.  * have open, determine if they are the same file.
  252.  * returns TRUE if they are the same, FALSE if different or an error
  253.  * (error in errno).
  254.  * XXX Need to make this format specific.  For now only works with
  255.  * XXX local files.
  256.  */
  257.  
  258. int
  259. local_same_file (name1, name2)
  260. char *name1, *name2;
  261. {
  262.     struct stat buf1, buf2;
  263.  
  264.     if (stat (name1, &buf1) != 0) {
  265.     return (FALSE);
  266.     }
  267.     if (stat (name2, &buf2) != 0) {
  268.     return (FALSE);
  269.     }
  270.     if ((buf1.st_dev == buf2.st_dev) && (buf1.st_ino == buf2.st_ino))
  271.     return (TRUE);
  272.     return (FALSE);
  273. }
  274.  
  275. char *
  276. local_backup_file (filename)
  277. char *filename;
  278. {
  279.     int err;
  280.     char *cp;
  281.     char backup[MAXPATHLEN];
  282.  
  283.     sprintf (backup, "%s~", filename);
  284.  
  285.     err = rename (filename, backup);
  286.     if (err < 0) {
  287.     cp = rindex (filename, '/');
  288.     if (cp == 0)
  289.         sprintf (backup, "#%s#", filename);
  290.     else {
  291.         strcpy (backup, filename);
  292.         sprintf (backup + (cp - filename) + 1, "#%s#", cp + 1);
  293.     }
  294.     err = rename (filename, backup);
  295.     }
  296.     
  297.     if (err < 0)
  298.     return 0;
  299.  
  300.     if (cp = malloc (strlen (backup) + 4)) {
  301.     strcpy (cp, backup);
  302.     return cp;
  303.     }
  304.     return 0;
  305. }
  306.  
  307.  
  308. /*
  309.  * record the mtime value for a mail file, so we can detect later on if
  310.  * some other process has changed the file.
  311.  */
  312. local_record_mtime (mf)
  313. msgvec *mf;
  314. {
  315.     struct stat sb;
  316.     if (stat (mf->filename, &sb) != 0) {
  317.     perror (mf->filename);
  318.     mf->mtime = 0;
  319.     }
  320.     else
  321.     mf->mtime = sb.st_mtime;
  322. }
  323.